#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <syslog.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include "pcap.h"
#include "worker.h"

#include "pkt_list.h"

void process_pkt(void *worker, u_char *buf, int len, int direct)
{
	u_short pkt_type;

	struct filtitem* pitem = NULL;
	u_char* eth_data = buf; //point to the header of ethernet
	struct iphdr*  iph = NULL;
	struct tcphdr* tcph = NULL;
	struct udphdr* udph = NULL;
	u_char* usr_data = NULL;//point to the header of data.
	u_short usr_data_len = 0;
	u_short eth_data_len = 14;
	u_short iphdr_len = 0;
	u_short hdr_len = 0;
	u_short sport,dport;
	int pdirect;

    int rc;

    char* url_data = NULL; 

	char *datah = NULL;


    pthread_t tid = pthread_self();
    FILE *fd;
    char strdaddr[20] = {0}, domainaddr[20] = {0};


    //printf("\n 111111111 \n");
    
	if (direct == 2) 
        direct = 1;
    
	if ((direct < 0) || (direct > 2))
		return;
    
	if (len <= eth_data_len)
		return;
    
	if (len > 1600)
		return;
    
	pkt_type = *(u_short *)(eth_data + 12);
	pkt_type = ntohs(pkt_type);
    
	if (0x8100 == pkt_type)
    {//VLAN
		pkt_type = ntohs(*(u_short *)(eth_data + 16));
		eth_data_len = 18;
		if (pkt_type != 0x0800){
			return;
		}
	}
    
	if (0x8847 == pkt_type)
    {//mpls
		eth_data_len = 18;
	}
	else
    {
		if (pkt_type != 0x0800)
        {
			return;
		}
	}
	//parse the ip datagram
	iph = (struct iphdr*)(eth_data + eth_data_len);
	iphdr_len = iph->ihl << 2;

	if (len <= eth_data_len + iphdr_len)
		return;
    
	if (ntohs(iph->tot_len) > 1600)
		return;
    
	if (IPPROTO_GRE == iph->protocol)
    {
		if((*((u_char*)iph + iphdr_len + 2) == 0x08) &&
		  (*((u_char*)iph + iphdr_len + 3) == 0x0))
		{
				iph = (struct iphdr*)((u_char*)iph+iphdr_len + 8);
		}
		else
        {
			return;
		}
	}

	if (IPPROTO_TCP == iph->protocol)
    {
		tcph = (struct tcphdr*)(((u_char*)iph) + iphdr_len);
		hdr_len = tcph->doff << 2;

		if(len<eth_data_len+iphdr_len+hdr_len)
			return;
        
		usr_data = (u_char*)tcph + hdr_len;
		usr_data_len = ntohs(iph->tot_len) - iphdr_len - hdr_len;
		sport=tcph->source;
		dport=tcph->dest;
	}
    else if (IPPROTO_UDP == iph->protocol)
    {
            udph=(struct udphdr*)(((u_char*)iph) + iphdr_len);
            
            hdr_len = sizeof(struct udphdr);
            usr_data = (u_char*)udph + hdr_len;
            usr_data_len = ntohs(iph->tot_len) - iphdr_len - hdr_len;
            sport=udph->source;
            dport=udph->dest;
            
            if(len<=eth_data_len+iphdr_len+hdr_len)
                return;
	}
    else
    {
        return;
    }

    if (IPPROTO_TCP == iph->protocol)
    {
        struct timeval time_v;
        gettimeofday(&time_v, NULL);


        char *p, *pp, httpbuf[1500], httpsendbuf[1600];

        char *pend, domaininfo[50];

        worker_process_pkt((worker_t *)worker, iph, tcph, usr_data, usr_data_len);

        
        httpbuf[1499] = 0;
        
    	memset(httpbuf, 0, 1500);
        memset(httpsendbuf, 0, 1600);
        memset(domaininfo, 0, 50);

    	//if(usr_data_len<=4 || usr_data_len>=1500) return;

        if (usr_data_len <= 4) return;
            
    }
    else
    {
        struct timeval time_v;
        gettimeofday(&time_v, NULL);
    }
    
    return ;

}

static void pkt_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
{
    worker_t *w = (worker_t*)user;

    process_pkt(w, (u_char *)bytes, h->len, 0);
}

       
int main(int argc, char *argv[])
{
    pcap_t *p;
    char errbuf[PCAP_ERRBUF_SIZE] = "";
    worker_t *w;
    struct bpf_program bpf;
    
    if (argc < 2)
    {
        printf("require a input device name\n");
        return 1;
    }

    worker_global_init();

    p = pcap_open_live(argv[1], 65536, 0, -1, errbuf);
    if (!p)
    {
        printf("unable to open %s, errbuf %s\n", argv[1], errbuf);
        return 1;
    }

    pcap_compile(p, &bpf, "ether dst 00:25:90:39:7F:0B and port 80", 0, PCAP_NETMASK_UNKNOWN);
    pcap_setfilter(p, &bpf);
    
    pcap_set_snaplen(p, 0);

    w = worker_create("eth0", 0);
    
    pcap_loop(p, -1, pkt_handler, (u_char*)w);

    pcap_close(p);

    sleep(3);
    //worker_dump(w);
    
}
